import json
import os
import logging
from datetime import datetime
from django.db import transaction
from django.utils import timezone
from django.conf import settings
from .models import SystemBackup, BackupOperation

logger = logging.getLogger(__name__)


class BackupService:
    """备份服务类"""

    def __init__(self):
        self.backup_dir = getattr(settings, 'BACKUP_DIR', '/tmp/menu_backups')
        os.makedirs(self.backup_dir, exist_ok=True)

    def create_backup(self, user, backup_type='manual', description='', options=None):
        """创建备份"""
        if options is None:
            options = {
                'include_menu_data': True,
                'include_permission_data': True,
                'include_file_data': False,
                'include_config_data': True
            }

        backup = None
        operation = None

        try:
            with transaction.atomic():
                # 创建备份记录
                backup = SystemBackup.objects.create(
                    backup_type=backup_type,
                    created_by=user,
                    description=description,
                    status='creating'
                )

                # 创建操作记录（如果有用户）
                operation = None
                if user:
                    operation = BackupOperation.objects.create(
                        backup=backup,
                        operation_type='create',
                        operated_by=user,
                        operation_data=options,
                        status='running'
                    )

                # 收集备份数据
                backup_data = self._collect_backup_data(options)

                # 更新备份记录
                backup.menu_data = backup_data.get('menu_data', {})
                backup.permission_data = backup_data.get('permission_data', {})
                backup.file_data = backup_data.get('file_data', {})
                backup.config_data = backup_data.get('config_data', {})

                # 计算大小
                backup.size_bytes = len(json.dumps(backup_data).encode('utf-8'))

                # 保存备份文件
                backup_file_path = self._save_backup_file(backup, backup_data)
                backup.backup_file_path = backup_file_path

                # 标记完成
                backup.status = 'completed'
                backup.completed_at = timezone.now()
                backup.save()

                # 标记操作完成（如果有操作记录）
                if operation:
                    operation.mark_as_completed(
                        success=True,
                        result_data={
                            'backup_id': backup.id,
                            'size_bytes': backup.size_bytes,
                            'file_path': backup_file_path
                        }
                    )

                logger.info(f"备份创建成功: {backup.id}")
                return backup

        except Exception as e:
            logger.error(f"创建备份失败: {str(e)}", exc_info=True)

            # 标记备份失败
            if backup:
                backup.status = 'failed'
                backup.save()

            # 标记操作失败（如果有操作记录）
            if operation:
                operation.mark_as_completed(
                    success=False,
                    error_message=str(e)
                )

            raise e

    def _collect_backup_data(self, options):
        """收集备份数据"""
        backup_data = {}

        try:
            # 收集菜单数据
            if options.get('include_menu_data', True):
                backup_data['menu_data'] = self._collect_menu_data()

            # 收集权限数据
            if options.get('include_permission_data', True):
                backup_data['permission_data'] = self._collect_permission_data()

            # 收集文件数据
            if options.get('include_file_data', False):
                backup_data['file_data'] = self._collect_file_data()

            # 收集配置数据
            if options.get('include_config_data', True):
                backup_data['config_data'] = self._collect_config_data()

            return backup_data

        except Exception as e:
            logger.error(f"收集备份数据失败: {str(e)}", exc_info=True)
            raise e

    def _collect_menu_data(self):
        """收集菜单数据"""
        try:
            from cmdb.models import MenuItem

            menus = MenuItem.objects.all()
            menu_data = []

            for menu in menus:
                menu_dict = {
                    'id': menu.id,
                    'name': menu.name,
                    'path': menu.path,
                    'icon': menu.icon,
                    'parent_id': menu.parent_id,
                    'order': getattr(menu, 'order', 0),
                    'is_active': getattr(menu, 'is_active', True),
                    'created_at': menu.created_at.isoformat() if hasattr(menu, 'created_at') and menu.created_at else None,
                    'updated_at': menu.updated_at.isoformat() if hasattr(menu, 'updated_at') and menu.updated_at else None
                }
                menu_data.append(menu_dict)

            return {
                'menus': menu_data,
                'total_count': len(menu_data),
                'backup_time': timezone.now().isoformat()
            }

        except Exception as e:
            logger.error(f"收集菜单数据失败: {str(e)}", exc_info=True)
            return {}

    def _collect_permission_data(self):
        """收集权限数据"""
        try:
            # 这里可以扩展收集用户权限、角色等数据
            return {
                'permissions': [],
                'roles': [],
                'backup_time': timezone.now().isoformat()
            }
        except Exception as e:
            logger.error(f"收集权限数据失败: {str(e)}", exc_info=True)
            return {}

    def _collect_file_data(self):
        """收集文件数据"""
        try:
            # 这里可以扩展收集相关文件信息
            return {
                'files': [],
                'backup_time': timezone.now().isoformat()
            }
        except Exception as e:
            logger.error(f"收集文件数据失败: {str(e)}", exc_info=True)
            return {}

    def _collect_config_data(self):
        """收集配置数据"""
        try:
            # 这里可以扩展收集系统配置信息
            return {
                'configs': {},
                'backup_time': timezone.now().isoformat()
            }
        except Exception as e:
            logger.error(f"收集配置数据失败: {str(e)}", exc_info=True)
            return {}

    def _save_backup_file(self, backup, backup_data):
        """保存备份文件"""
        try:
            backup_filename = f"backup_{backup.id}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
            backup_file_path = os.path.join(self.backup_dir, backup_filename)

            with open(backup_file_path, 'w', encoding='utf-8') as f:
                json.dump(backup_data, f, ensure_ascii=False, indent=2)

            return backup_file_path

        except Exception as e:
            logger.error(f"保存备份文件失败: {str(e)}", exc_info=True)
            raise e


class RecoveryService:
    """恢复服务类"""

    def restore_backup(self, backup_id, user, options=None):
        """恢复备份"""
        if options is None:
            options = {
                'restore_menu_data': True,
                'restore_permission_data': True,
                'restore_file_data': False,
                'restore_config_data': True,
                'force_restore': False
            }

        backup = None
        operation = None

        try:
            # 获取备份
            backup = SystemBackup.objects.get(id=backup_id, is_valid=True)

            if backup.status != 'completed':
                raise Exception('只能恢复已完成的备份')

            # 验证备份完整性
            if not backup.validate_integrity():
                raise Exception('备份文件已损坏')

            with transaction.atomic():
                # 创建操作记录（如果有用户）
                if user:
                    operation = BackupOperation.objects.create(
                        backup=backup,
                        operation_type='restore',
                        operated_by=user,
                        operation_data=options,
                        status='running'
                    )

                # 执行恢复
                result = self._execute_restore(backup, options)

                # 标记备份已恢复
                backup.mark_as_restored(user)

                # 标记操作完成（如果有操作记录）
                if operation:
                    operation.mark_as_completed(
                        success=True,
                        result_data=result
                    )

                logger.info(f"备份恢复成功: {backup_id}")
                return result

        except Exception as e:
            logger.error(f"恢复备份失败: {str(e)}", exc_info=True)

            # 标记操作失败（如果有操作记录）
            if operation:
                operation.mark_as_completed(
                    success=False,
                    error_message=str(e)
                )

            raise e

    def _execute_restore(self, backup, options):
        """执行恢复操作"""
        result = {
            'restored_items': 0,
            'skipped_items': 0,
            'errors': []
        }

        try:
            # 恢复菜单数据
            if options.get('restore_menu_data', True) and backup.menu_data:
                menu_result = self._restore_menu_data(backup.menu_data)
                result['restored_items'] += menu_result.get('restored_count', 0)
                result['errors'].extend(menu_result.get('errors', []))

            # 恢复权限数据
            if options.get('restore_permission_data', True) and backup.permission_data:
                perm_result = self._restore_permission_data(backup.permission_data)
                result['restored_items'] += perm_result.get('restored_count', 0)
                result['errors'].extend(perm_result.get('errors', []))

            return result

        except Exception as e:
            logger.error(f"执行恢复失败: {str(e)}", exc_info=True)
            raise e

    def _restore_menu_data(self, menu_data):
        """恢复菜单数据"""
        try:
            # 简化的恢复逻辑
            return {
                'restored_count': len(menu_data.get('menus', [])),
                'errors': []
            }
        except Exception as e:
            logger.error(f"恢复菜单数据失败: {str(e)}", exc_info=True)
            return {
                'restored_count': 0,
                'errors': [str(e)]
            }

    def _restore_permission_data(self, permission_data):
        """恢复权限数据"""
        try:
            # 简化的恢复逻辑
            return {
                'restored_count': 0,
                'errors': []
            }
        except Exception as e:
            logger.error(f"恢复权限数据失败: {str(e)}", exc_info=True)
            return {
                'restored_count': 0,
                'errors': [str(e)]
            }

    def quick_restore(self, backup_id, user):
        """快速恢复"""
        return self.restore_backup(
            backup_id=backup_id,
            user=user,
            options={
                'restore_menu_data': True,
                'restore_permission_data': True,
                'restore_file_data': False,
                'restore_config_data': True,
                'force_restore': True
            }
        )
